package com.nova.bluetooth.xunFeiSDK.util;


import android.util.Pair;


import com.nova.bluetooth.helpUtils.LogUtil;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
//
//import ws.schild.jave.Encoder;
//import ws.schild.jave.EncoderException;
//import ws.schild.jave.MultimediaObject;
//import ws.schild.jave.encode.AudioAttributes;
//import ws.schild.jave.encode.EncodingAttributes;

public class ConvertUtils {
    public static void convertWav2Pcm(String wavFilePath, String pcmFilePath) throws IOException {
        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            fis = new FileInputStream(wavFilePath);
            fos = new FileOutputStream(pcmFilePath);

            // Read the WAV file header (44 bytes)
            byte[] header = new byte[44];
            if (fis.read(header) != 44) {
                throw new IOException("Invalid WAV file header");
            }

            // Check if it is a valid WAV file
            if (header[0] != 'R' || header[1] != 'I' || header[2] != 'F' || header[3] != 'F') {
                throw new IOException("Not a valid WAV file");
            }

            // Skip the rest of the header and read the audio data
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                fos.write(buffer, 0, bytesRead);
            }
        } finally {
            if (fis != null) {
                fis.close();
            }
            if (fos != null) {
                fos.close();
            }
        }
    }

    /**
     * 转换音频文件
     *
     * @param src    需要转换的pcm音频路径
     * @param target 保存转换后wav格式的音频路径
     * @throws Exception
     */
    public static void convertPcm2Wav(String src, String target) throws Exception {
        FileInputStream fis = new FileInputStream(src);
        FileOutputStream fos = new FileOutputStream(target + ".wav");  //+".wav"

        //计算长度
        byte[] buf = new byte[1024 * 4];
        int size = fis.read(buf);
        int PCMSize = 0;
        while (size != -1) {
            PCMSize += size;
            size = fis.read(buf);
        }
        fis.close();

        //填入参数，比特率等等。这里用的是16位单声道 8000 hz
        WaveHeader header = new WaveHeader();
        //长度字段 = 内容的大小（PCMSize) + 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节)
        header.fileLength = PCMSize + (44 - 8);
        header.FmtHdrLeth = 16;
        header.BitsPerSample = 16;
        header.Channels = 2;
        header.FormatTag = 0x0001;
        header.SamplesPerSec = 8000;
        header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8);
        header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
        header.DataHdrLeth = PCMSize;

        byte[] h = header.getHeader();

        assert h.length == 44; //WAV标准，头部应该是44字节
        //write header
        fos.write(h, 0, h.length);
        //write data stream
        fis = new FileInputStream(src);
        size = fis.read(buf);
        while (size != -1) {
            fos.write(buf, 0, size);
            size = fis.read(buf);
        }
        fis.close();
        fos.close();
        System.out.println("Convert OK!");
    }

    /**
     * 将录制pcm数据 加一个 wav44字节头部 转换为真正意义上的wav
     *
     * @param src 录制wav路径
     * @throws Exception
     */
    public static Pair<Boolean, String> pcmDataToWav(String src) {
        LogUtil.d("src = " + src);
        String target = src.substring(0, src.length() - 4) + ".wav";
        LogUtil.d("target = " + target);
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream(src);
            fos = new FileOutputStream(target);  //+".wav"
            //计算长度
            byte[] buf = new byte[1024 * 4];
            int size = fis.read(buf);
            int PCMSize = 0;
            while (size != -1) {
                PCMSize += size;
                size = fis.read(buf);
            }
            fis.close();

            //填入参数，比特率等等。这里用的是16位单声道 8000 hz
            WaveHeader header = new WaveHeader();
            //长度字段 = 内容的大小（PCMSize) + 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节)
            header.fileLength = PCMSize + (44 - 8);
            header.FmtHdrLeth = 16;
            header.BitsPerSample = 16;
            header.Channels = 2;
            header.FormatTag = 0x0001;
            header.SamplesPerSec = 8000;
            header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8);
            header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
            header.DataHdrLeth = PCMSize;

            byte[] h = header.getHeader();

            assert h.length == 44; //WAV标准，头部应该是44字节
            //write header
            fos.write(h, 0, h.length);
            //write data stream
            fis = new FileInputStream(src);
            size = fis.read(buf);
            while (size != -1) {
                fos.write(buf, 0, size);
                size = fis.read(buf);
            }
            fos.flush();
            System.out.println("Convert OK!");
            return Pair.create(true, target);
        } catch (Exception e) {
            return Pair.create(false, null);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }


//        int PCMSize = (int) new File(src).length();
////        //填入参数，比特率等等。这里用的是16位单声道 8000 hz
//        WaveHeader header = new WaveHeader();
//        //长度字段 = 内容的大小（PCMSize) + 头部字段的大小(不包括前面4字节的标识符RIFF以及fileLength本身的4字节)
//        header.fileLength = PCMSize + (44 - 8);
//        header.FmtHdrLeth = 16;
//        header.BitsPerSample = 16;
//        header.Channels = 1; //声道
//        header.FormatTag = 0x0001;
//        header.SamplesPerSec = 16000;
//        header.BlockAlign = (short) (header.Channels * header.BitsPerSample / 8);
//        header.AvgBytesPerSec = header.BlockAlign * header.SamplesPerSec;
//        header.DataHdrLeth = PCMSize;
//
//        try {
//            FileOutputStream fos = new FileOutputStream(src, true);
//            byte[] h = header.getHeader();
//            assert h.length == 44; //WAV标准，头部应该是44字节
//            fos.write(h, 0, h.length);
//            fos.flush();
//            fos.close();
//            System.out.println("Convert OK!");
//            return true;
//        } catch (IOException e) {
//            return false;
//        }


//        int totalAudioLen =  PCMSize;
//        int sampleRate = 16000;
//        int channels = 1;
//        int sampleFormat = 16;
//
//        long totalDataLen = PCMSize + 36;
//        long byteRate = sampleRate * channels * sampleFormat / 8;
//
//        byte[] header = new byte[44];
//        header[0] = 'R'; // RIFF/WAVE header
//        header[1] = 'I';
//        header[2] = 'F';
//        header[3] = 'F';
//        header[4] = (byte) (totalDataLen & 0xff);
//        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
//        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
//        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
//        header[8] = 'W';
//        header[9] = 'A';
//        header[10] = 'V';
//        header[11] = 'E';
//        header[12] = 'f'; // 'fmt ' chunk
//        header[13] = 'm';
//        header[14] = 't';
//        header[15] = ' ';
//        header[16] = 16; // 16 for PCM
//        header[17] = 0;
//        header[18] = 0;
//        header[19] = 0;
//        header[20] = 1; // 1 for PCM
//        header[21] = 0;
//        header[22] = (byte) channels;
//        header[23] = 0;
//        header[24] = (byte) (sampleRate & 0xff);
//        header[25] = (byte) ((sampleRate >> 8) & 0xff);
//        header[26] = (byte) ((sampleRate >> 16) & 0xff);
//        header[27] = (byte) ((sampleRate >> 24) & 0xff);
//        header[28] = (byte) (byteRate & 0xff);
//        header[29] = (byte) ((byteRate >> 8) & 0xff);
//        header[30] = (byte) ((byteRate >> 16) & 0xff);
//        header[31] = (byte) ((byteRate >> 24) & 0xff);
//        header[32] = (byte) (channels * sampleFormat / 8); // block align
//        header[33] = 0;
//        header[34] = (byte) sampleFormat; // bits per sample
//        header[35] = 0;
//        header[36] = 'd';
//        header[37] = 'a';
//        header[38] = 't';
//        header[39] = 'a';
//        header[40] = (byte) (totalAudioLen & 0xff);
//        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
//        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
//        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
//        fos.write(header, 0, header.length);
//        fos.flush();
//        fos.close();
//        //write header
//        fos.write(h, 0, h.length);
//        //write data stream
//        fis = new FileInputStream(src);
//        size = fis.read(buf);
//        while (size != -1) {
//            fos.write(buf, 0, size);
//            size = fis.read(buf);
//        }
//        fis.close();
    }

    public static class WaveHeader {

        public final char fileID[] = {'R', 'I', 'F', 'F'};
        public int fileLength;
        public char wavTag[] = {'W', 'A', 'V', 'E'};
        ;
        public char FmtHdrID[] = {'f', 'm', 't', ' '};
        public int FmtHdrLeth;
        public short FormatTag;
        public short Channels;
        public int SamplesPerSec;
        public int AvgBytesPerSec;
        public short BlockAlign;
        public short BitsPerSample;
        public char DataHdrID[] = {'d', 'a', 't', 'a'};
        public int DataHdrLeth;

        public byte[] getHeader() throws IOException {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            WriteChar(bos, fileID);
            WriteInt(bos, fileLength);
            WriteChar(bos, wavTag);
            WriteChar(bos, FmtHdrID);
            WriteInt(bos, FmtHdrLeth);
            WriteShort(bos, FormatTag);
            WriteShort(bos, Channels);
            WriteInt(bos, SamplesPerSec);
            WriteInt(bos, AvgBytesPerSec);
            WriteShort(bos, BlockAlign);
            WriteShort(bos, BitsPerSample);
            WriteChar(bos, DataHdrID);
            WriteInt(bos, DataHdrLeth);
            bos.flush();
            byte[] r = bos.toByteArray();
            bos.close();
            return r;
        }

        private void WriteShort(ByteArrayOutputStream bos, int s) throws IOException {
            byte[] mybyte = new byte[2];
            mybyte[1] = (byte) ((s << 16) >> 24);
            mybyte[0] = (byte) ((s << 24) >> 24);
            bos.write(mybyte);
        }


        private void WriteInt(ByteArrayOutputStream bos, int n) throws IOException {
            byte[] buf = new byte[4];
            buf[3] = (byte) (n >> 24);
            buf[2] = (byte) ((n << 8) >> 24);
            buf[1] = (byte) ((n << 16) >> 24);
            buf[0] = (byte) ((n << 24) >> 24);
            bos.write(buf);
        }

        private void WriteChar(ByteArrayOutputStream bos, char[] id) {
            for (int i = 0; i < id.length; i++) {
                char c = id[i];
                bos.write(c);
            }
        }

    }


    public static void WavToPcm(String src, String target) {
        try {
            FileInputStream fis = new FileInputStream(src);
            FileOutputStream fos = new FileOutputStream(target);
            byte[] buf = new byte[1024 * 4];
            int size = fis.read(buf);
            fos.write(buf, 44, size - 44);
            size = fis.read(buf);
            while (size != -1) {
                fos.write(buf, 0, size);
                size = fis.read(buf);
            }
            fis.close();
            fos.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 文件格式转换
     * @param source 源文件
     * @param desFileName 转换后的wav文件的路径
     */
//    public static File transformation(File source, String desFileName) throws EncoderException, IOException {
//        Encoder encoder = new Encoder();
//        // 创建一个临时文件
//        File target = File.createTempFile(desFileName, "wav");
//        // 在虚拟机终止时，请求删除此抽象路径名表示的文件或目录。
//        target.deleteOnExit();
//        // File target = new File(desFileName);
//        // 创建音频属性实例
//        AudioAttributes audio = new AudioAttributes();
//
//        // 设置编码 libmp3lame pcm_s16le
//        audio.setCodec("pcm_s16le");
//        // 音频比特率
//        audio.setBitRate(16000);
//        // 声道 1 =单声道，2 =立体声
//        audio.setChannels(2);
//        // 采样率
//        audio.setSamplingRate(16000);
//        // 转码属性实例
//        EncodingAttributes attrs = new EncodingAttributes();
//        // 转码格式
//        attrs.setOutputFormat("wav");
//        attrs.setAudioAttributes(audio);
//
//        MultimediaObject sourceObj = new MultimediaObject(source);
//        encoder.encode(sourceObj, target, attrs);
//        return target;
//    }

    /**
     * @param fos           要将 WAV 文件头写入的文件输出流
     * @param channels      声道数，通常为 1（单声道）或 2（立体声）
     * @param sampleRate    采样率，通常为 44100 Hz（标准的 CD 质量）或其他采样率
     * @param sampleFormat  每个样本的位数，通常为 16 位（AudioFormat.ENCODING_PCM_16BIT）
     * @param totalAudioLen 音频数据的总长度，不包括 WAV 文件头部分
     * @throws IOException
     */
    public static void writeWavHeader(FileOutputStream fos, int channels, int sampleRate, int sampleFormat,
                                      int totalAudioLen) throws IOException {
        long totalDataLen = totalAudioLen + 36;
        long byteRate = sampleRate * channels * sampleFormat / 8;

        byte[] header = new byte[44];
        header[0] = 'R'; // RIFF/WAVE header
        header[1] = 'I';
        header[2] = 'F';
        header[3] = 'F';
        header[4] = (byte) (totalDataLen & 0xff);
        header[5] = (byte) ((totalDataLen >> 8) & 0xff);
        header[6] = (byte) ((totalDataLen >> 16) & 0xff);
        header[7] = (byte) ((totalDataLen >> 24) & 0xff);
        header[8] = 'W';
        header[9] = 'A';
        header[10] = 'V';
        header[11] = 'E';
        header[12] = 'f'; // 'fmt ' chunk
        header[13] = 'm';
        header[14] = 't';
        header[15] = ' ';
        header[16] = 16; // 16 for PCM
        header[17] = 0;
        header[18] = 0;
        header[19] = 0;
        header[20] = 1; // 1 for PCM
        header[21] = 0;
        header[22] = (byte) channels;
        header[23] = 0;
        header[24] = (byte) (sampleRate & 0xff);
        header[25] = (byte) ((sampleRate >> 8) & 0xff);
        header[26] = (byte) ((sampleRate >> 16) & 0xff);
        header[27] = (byte) ((sampleRate >> 24) & 0xff);
        header[28] = (byte) (byteRate & 0xff);
        header[29] = (byte) ((byteRate >> 8) & 0xff);
        header[30] = (byte) ((byteRate >> 16) & 0xff);
        header[31] = (byte) ((byteRate >> 24) & 0xff);
        header[32] = (byte) (channels * sampleFormat / 8); // block align
        header[33] = 0;
        header[34] = (byte) sampleFormat; // bits per sample
        header[35] = 0;
        header[36] = 'd';
        header[37] = 'a';
        header[38] = 't';
        header[39] = 'a';
        header[40] = (byte) (totalAudioLen & 0xff);
        header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
        header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
        header[43] = (byte) ((totalAudioLen >> 24) & 0xff);

        fos.write(header, 0, 44);
    }

    // 更新 WAV 文件头以包含实际的音频数据长度
    public static void updateWavHeader(File file, long totalAudioLen) {
        try {
            RandomAccessFile wavFile = new RandomAccessFile(file, "rw");

            // 跳过 WAV 文件头的前四个字节（总数据长度）
            wavFile.seek(4);
            // 写入新的总数据长度（音频数据长度 + 36）
            wavFile.write(intToByteArray(totalAudioLen + 36), 0, 4);

            // 跳过 WAV 文件头的第40至43字节（音频数据长度）
            wavFile.seek(40);
            // 写入新的音频数据长度
            wavFile.write(intToByteArray(totalAudioLen), 0, 4);

            wavFile.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static byte[] intToByteArray(long value) {
        byte[] byteArray = new byte[4];
        byteArray[0] = (byte) (value & 0xFF);
        byteArray[1] = (byte) ((value >> 8) & 0xFF);
        byteArray[2] = (byte) ((value >> 16) & 0xFF);
        byteArray[3] = (byte) ((value >> 24) & 0xFF);
        return byteArray;
    }

}


